'''
'''
from PyQt4.QtCore import QObject, SIGNAL
from SimpleCells.Components.Table.SCTableViewTools import SCTableReadTools
from SimpleCells.Components.List.SCListData import SCListDict

try:
    from numpy import array
except:
    array = None

def putWarning(message):
    print '(warning) %s' % message

def putError(message):
    raise Exception(message)

class SCTableModelReader(QObject):
    '''A class for accessing table data from the python interpreter.'''
    def __init__(self, model,parent=None):
        QObject.__init__(self,parent)
        self.__model = model
    
    def __repr__(self):
        return QObject.__repr__(self)+'\n\nLabels: '+', '.join(self.labels())
    
    def model(self):
        return self.__model

    def __readSlices__(self,row,col):
        out = []
        if isinstance(row,slice) and isinstance(col,slice):
            for i in range(self.__model.rowCount())[row]:
                out.append([])
                for j in range(self.__model.columnCount())[col]:
                    out[-1].append(self.__model.evalCell(i,j))
        elif isinstance(row,slice):
            for i in range(self.__model.rowCount())[row]:
                out.append(self.__model.evalCell(i,col))
        else:
            for j in range(self.__model.columnCount())[col]:
                out.append(self.__model.evalCell(row,j))
        return out

    def __rawRead__(self,name):
        if self.__model.hasLabel(name):
            return self.__model.readDataFromLabel(name)
        elif hasattr(name,'__iter__'):
            row, col = name
            if isinstance(row,slice) or isinstance(col,slice):
                return self.__readSlices__(row, col)
            return self.__model.evalCell(row,col)
        putError("Can't read '%s', this label doesn't exist." % name)

    def __getitem__(self, name):
        trueName = name
        if self.__model.hasLabel(trueName):
            trueName = self.__model.labelAka(name)
        if self.__model.hasLabel(trueName) and \
            self.__model.labelShapeHint(trueName):
            return self.__call__(trueName,\
                    option=self.__model.labelShapeHint(trueName))
        return self.__rawRead__(trueName)

    def __writeSlices__(self,row,col,data):
        if isinstance(row,slice) and isinstance(col,slice):
            for iCount, i in enumerate(range(self.__model.rowCount())[row]):
                for jCount, j in enumerate(range(self.__model.columnCount())[col]):
                    value = None
                    if hasattr(data,'next'):
                        value = data.next()                    
                    elif hasattr(data,'__iter__'): 
                        value = data[iCount][jCount]
                    else: value = data
                    self.__model.setCell(i,j,value)
        elif isinstance(row,slice):
            for iCount, i in enumerate(range(self.__model.rowCount())[row]):
                value = None
                if hasattr(data,'next'):
                    value = data.next()
                elif hasattr(data,'__iter__'):
                    value = data[iCount]
                else:
                    value = data
                self.__model.setCell(i,col,value)
        else:
            for jCount, j in enumerate(range(self.__model.columnCount())[col]):
                value = None
                if hasattr(data,'next'):
                    value = data.next()
                elif hasattr(data,'__iter__'):
                    value = data[jCount]
                else:
                    value = data
                self.__model.setCell(row,j,value)
    
    def __rowColWrite__(self,row,col,data):
        if isinstance(row,slice) or isinstance(col,slice):
            self.__writeSlices__(row,col,data)
        else:
            self.__model.setCell(row,col,data)
    
    def __setitem__(self,name,data):
        trueName = name
        if self.__model.hasLabel(trueName):
            trueName = self.__model.labelAka(name)
        if self.__model.hasLabel(trueName):
            self.__model.writeDataToLabel(trueName,data)
            self.emit(SIGNAL("tableChanged()"))
        elif hasattr(name,'__iter__'):
            row, col = name
            self.__rowColWrite__(row,col,data)
            self.emit(SIGNAL("tableChanged()"))
        else:
            putWarning("Can't set '%s', this label doesn't exist." % name)

    def __delitem__(self,name):
        if self.__model.hasLabel(name):
            self.__model.writeDataToLabel(name,None)
            self.__model.delLabel(name)
        elif hasattr(name,'__iter__'):
            row, col = name
            self.__model.setCell(row,col,None)
        self.emit(SIGNAL("tableChanged()"))

    def __iter__(self):
        return iter(self.__model.labels())

    def __call__(self, name = 'all', option = 's', **kwargs):
        if name == 'all': 
            return self.toDict()
        out = self.__rawRead__(name)
        opts = option.split('+')
        if 's' in opts or 'simplify' in opts:
            out = SCTableReadTools.simplifyShape(out)
        if 't' in opts or 'tuple' in opts:
            out = tuple(out)
        if ('a' in opts or 'array' in opts):
            if array:
                out = array(out)
            else:
                putWarning("Numpy is required to use option 'array'.")
        return out

    def labels(self):
        '''Returns a list of the table labels'''
        return self.__model.labels().keys()
    
    def has_key(self,key):
        return self.hasLabel(key)

    def hasLabel(self,name):
        '''Checks if table contains the given label.'''
        return self.__model.hasLabel(name)

    def clear(self, *labels):
        '''Removes data from given label.
        
        @param labels, a tuple of labels defined on the table.
        '''
        for label in labels:
            self.__model.clearLabelData(label)
    
    def clearAll(self):
        '''Removes data from all labels on table.
        '''
        self.__model.clearAllLabelData()

    def append(self, label, value):
        '''Appends data to a label queue.
        '''
        if hasattr(value,'__iter__'):
            for val in value: self.append(label,val)
        else:
            tmpVal = self.__getitem__(label)
            tmpVal.append(value)
            self.__setitem__(label,tmpVal)
    
    def shape(self, name):
        '''Returns the shape of the data.
        '''
        tmp = self.__getitem__(name)
        if hasattr(tmp,'__iter__'):
            if hasattr(tmp[0],'__iter__'):
                return (len(tmp),len(tmp[0]))
            return (len(tmp),)
        return ()
        
    def toDict(self,skip=[],just=[]):
        '''Returns a dict with contents of the table.
        
        @param skip, a list of keys to skip.
        '''
        out = {}
        if not just:
            for label in self.labels():
                if label in skip: continue
                out[label] = self.__getitem__(label)
        else:
            for label in just:
                out[label] = self.__getitem__(label)
        return out

class SCWorkspace(dict):
    '''The SimpleCells workspace handler.'''
    PROTECTED_NAMES = ('table','free','__actions__')
    def __init__(self,modelReader,listDict):
        dict.__init__(self)
        self.__table = modelReader
        self.__free = listDict
        self['table'] = self.__table
        self['free'] = self.__free
        self['__actions__'] = []

    def __delitem__(self,name):
        if name in  SCWorkspace.PROTECTED_NAMES:
            putWarning('This name is protected and cannot be deleted.')
        else:
            dict.__delitem__(self,name)
